package web.beans;

import ejb.entities.Event;
import ejb.entities.Invitation;
import ejb.entities.User;
import ejb.entities.WeatherForecast;
import ejb.facade.EventFacade;
import ejb.facade.InvitationFacade;
import ejb.facade.UserFacade;
import ejb.facade.WeatherFacade;
import ejb.facade.WeatherFacadeImp;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.inject.Named;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;


@SessionScoped
@Named("loginBean")
public class LoginBean implements Login,Serializable{
    
    private String username;
    private String password;
    
    private User user;
    
    private int eventSelected;
    private String titleSelected;
    private Date dateStartSelected;
    private Date dateEndSelected;
    
    private int notifyCounter;
    private int badweatherCounter;
    
    private boolean notifyUp;
    
    private boolean firstAccessUp;
    
    @EJB
    private UserFacade userFacade;
    @EJB
    private InvitationFacade inFacade;
    @EJB
    private EventFacade evFacade;
    @EJB
    private WeatherFacade weaFacade;
        
    public LoginBean() {
        this.eventSelected = -1;
        this.notifyCounter = 0;
        this.notifyUp = false;
        this.firstAccessUp = true;
    }
    
    public void loginClear(){
        this.eventSelected = -1;
        this.notifyCounter = 0;
        this.notifyUp = false;
        this.firstAccessUp = true;
        this.setUser(null);
        this.setUsername("");
    }
    
    //GETTER Functions
    
    @Override
    public String getTitleSelected() {
        return titleSelected;
    }

    @Override
    public Date getDateStartSelected() {
        return dateStartSelected;
    }

    @Override
    public Date getDateEndSelected() {
        return dateEndSelected;
    }


    @Override
    public int getBadweatherCounter() {    
        return badweatherCounter;
    }

    @Override
    public boolean isFirstAccessUp() {
        return firstAccessUp;
    }

    @Override
    public boolean isNotifyUp() {
        return notifyUp;
    }

    @Override
    public int getEventSelected() {
        return eventSelected;
    }

    @Override
    public int getNotifyCounter() {
        return notifyCounter;
    }

    public String getUsername() {
        return this.username;
    }
    
    public String getPassword() {
        return this.password;
    }

    @Override
      public User getUser() {
	if (user == null && isLoged()) {
		user = userFacade.findUserByUsername(getPrincipalName());
	}
	return user;
    }
      
    public UserFacade getUserFacade() {
        return userFacade;
    }
        
    //SETTER Functions

    @Override
    public void setTitleSelected(String titleSelected) {
        this.titleSelected = titleSelected;
    }

    @Override
    public void setDateStartSelected(Date dateStartSelected) {
        this.dateStartSelected = dateStartSelected;
    }

    @Override
    public void setDateEndSelected(Date dateEndSelected) {
        this.dateEndSelected = dateEndSelected;
    }

    @Override
    public void setBadweatherCounter(int badweatherCounter) {
        this.badweatherCounter = badweatherCounter;
    }
   
    @Override
    public void setFirstAccessUp(boolean firstAccessUp) {
        this.firstAccessUp = firstAccessUp;
    }

    @Override
    public void setNotifyUp(boolean notifyUp) {
        this.notifyUp = notifyUp;
    }
     
    @Override
    public void setNotifyCounter(int notifyCounter) {
        this.notifyCounter = notifyCounter;
    }

    @Override
    public void setEventSelected(int eventSelected) {
        this.eventSelected = eventSelected;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public void setUser(User user) {
        this.user = user;
    }

    public void setUserFacade(UserFacade userFacade) {
        this.userFacade = userFacade;
    }
    //Bean Functions
    
    public void login() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        //this.password=this.encryptPsw(this.password); 
        if(this.getUser()!= null){                      
            this.logout();
        }
        if(this.username==null || this.password==null){
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!", "Username and Password are Required!"));
        }else{
            try {
                request.login(this.username, this.password);
                this.setUser(userFacade.findUserByUsername(this.username));
                readInvitationsStartup();
                badWeatherAlertsStartup();
                goToHome();
            } catch (ServletException e) {
                if(e.getMessage().equals("This is request has already been authenticated")){
                        goToHome();
                }else{                       
                    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!", "Wrong username or Password!"));	 
                }
            }     
        }
    }

    public String logout() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        try {
            loginClear();
            request.logout();
            this.loginClear();
        } catch (ServletException e) {
            context.addMessage(null, new FacesMessage("Logout failed."));
        }
        return "/index";
    }
    
    @Override
    	public Boolean isLoged() {
		if (user != null)
			return true;

		ExternalContext context = FacesContext.getCurrentInstance()
				.getExternalContext();
		if (context != null && context.getUserPrincipal() != null
				&& context.getUserPrincipal().getName() != "")
			return true;

		return false;
	}
        
       
    @Override
	public String getUserFullName() {
		if (isLoged()){
			return getUser().getFullName();
		}
            return "";
        }
        
      
    @Override
	public void refreshUser() {
		if(isLoged() && user != null && !"".equals(user.getUsername()))
		{
			user = userFacade.findUserByUsername(user.getUsername());
		}
		
	}
        
        public String getPrincipalName() {
            ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
            return context.getUserPrincipal().getName();
	}
        
        public void goToNotifyCenter(){
            redirect("user_notifyCenter");
        }
        
    @Override
        public void goToHome(){
            redirect("/user/home.xhtml");
        }
        
    @Override
        public void goToProfile(){
            redirect("/user/user_profile.xhtml");
        }
        
    @Override
        public void goToRegister(){
            redirect("register.xhtml");
        }
        
    @Override
        public void goToNewEvent(){
            redirect("user_addNewEvent");
        }
        
        @Override
        public void goToManagerEvent(){
            redirect("user_eventManager");
        }
        
    @Override
        public void goToIndex(){
            redirect("index.xhtml");
        }
        
        public void redirect(String outcome) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, outcome);
        }
        
        public String encryptPsw(String clearPsw)
        {
            try {
                MessageDigest digest = MessageDigest.getInstance("SHA-256");
                byte[] hash = digest.digest(clearPsw.getBytes("UTF-8"));
                BigInteger bigInt = new BigInteger(1, hash);
                clearPsw = bigInt.toString(16);
            } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
                Logger.getLogger(User.class.getName()).log(Level.SEVERE, null, ex);
            }
            return clearPsw;
        }
        
        
    @Override
        public Date getToday(){
                //DateFormat stringFormat = new SimpleDateFormat("dd/MM/yyyy");
                Calendar cal = Calendar.getInstance(); 
                cal.set(Calendar.DATE, cal.get(Calendar.DATE));
                return cal.getTime();
        }
        
        @Override
        public Date getTomorrow(){
                //DateFormat stringFormat = new SimpleDateFormat("dd/MM/yyyy");
                Calendar cal = Calendar.getInstance(); 
                cal.set(Calendar.DATE, cal.get(Calendar.DATE) + 1);
                return cal.getTime();
        }
        
        @Override
        public Date fromDateTimetoDate(Date datetime){
                DateFormat stringFormat = new SimpleDateFormat("dd/MM/yyyy");
                String forecastStr = stringFormat.format(datetime);
                Date onlyDate = new Date();
                try {
                    onlyDate = stringFormat.parse(forecastStr);
                } catch (ParseException ex) {
                      Logger.getLogger(WeatherFacadeImp.class.getName()).log(Level.SEVERE, null, ex);
                }
               return onlyDate;
        }
        
       @Override
        public void setEventSelected(String title, Date dateStart, Date dateEnd){
          this.titleSelected = title;
          this.dateStartSelected = dateStart;
          this.dateEndSelected = dateEnd; 
        }
        
         public void readInvitationsStartup(){
            int counter=0;
            for (Invitation inv : inFacade.findInvitationByUserAfterToday(getUser())){
                if(inv.getInvstate().equals("P")){
                    counter++;
                }
            }
            if(getNotifyCounter()<counter){
                setNotifyUp(true);
            }
            setNotifyCounter(counter);
        }
         
        public void badWeatherAlertsStartup(){
            this.updateMyWeatherForecast();
            int counter=0;
            for (Event ev : evFacade.findMyEventWithBadWeatherOneDayBeforeToday())
            {
                    counter++; 
            }
            if(getBadweatherCounter()<counter){
                setNotifyUp(true);
            }
            setBadweatherCounter(counter);          
        }
        
        public void updateMyWeatherForecast(){
            for (Event ev : evFacade.findMyEventOfTomorrow())
            {
                    WeatherForecast weatherfore = weaFacade.getDailyWeatherForecast(ev.getCity(), ev.getDateTimeEnd(), true);
                    weatherfore.setIdWeather(ev.getIdWeather().getIdWeather());
                    weaFacade.update(weatherfore);
            }
        }
}

